<template>
  <div v-if="isLoading" class="d-cprender-loading">
    <RotorIcon v-if="isShowLoadingIcon" class="dam-rotating" /><span v-if="isShowLoadingText">加载中...</span>
    <slot name="loading"></slot>
  </div>
  <component v-else
    :is="component.component"
    v-bind="$props"
    @update="handleUpdate"
    @hook:created="triggerEvent('created', $children)"
    @hook:beforeMount="triggerEvent('beforeMount', $children)"
    @hook:mounted="triggerEvent('mounted', $children)"
    @hook:beforeDestroy="triggerEvent('beforeDestroy', $children)"
    @hook:destroyed="triggerEvent('destroyed', $children)"
    ref="view">
    <slot></slot>
  </component>
</template>

<script>
import { coder, domer } from '@daelui/dogjs/dist/components'
import { RotorIcon } from '@daelui/vdog/dist/icons'
import { getComponent, getPropertyComponent } from './repository.js'

export default {
  components: {
    RotorIcon
  },

  props: {
    cpr: {
      type: Object,
      default () {
        return {
          component: 'div',
          isProperty: false
        }
      }
    },
    properts: {
      default() {
        return {}
      }
    },
    layout: {
      type: Object,
      default() {
        return {}
      }
    },
    events: {
      default() {
        return {}
      }
    },
    resource: {
      default() {
        return {}
      }
    },
    theme: {
      default() {
        return {}
      }
    },
    childComponents: {
      default() {
        return []
      }
    },
    value: {
      default() {
        return {}
      }
    },
    isShowLoadingIcon: {
      type: Boolean,
      default: true
    },
    isShowLoadingText: {
      type: Boolean,
      default: true
    }
  },

  data () {
    return {
      component: {
        // 动态组件
        component: 'div'
      },
      isLoading: true // 加载中
    }
  },

  watch: {
    cpr: {
      handler () {
        this.syncComponent()
      },
      deep: true
    },
    value: {
      handler () {
        this.syncComponent()
      },
      deep: true
    }
  },

  methods: {
    // 属性更新
    handleUpdate (data) {
      this.$emit('update', data)
    },
    // 同步组件
    syncComponent () {
      let result = this.cpr.isProperty ?
        getPropertyComponent(this.cpr) :
        getComponent(this.cpr)
      this.cpr.version = result.version
      this.component.component = result.component
    },
    // 触发自定义事件
    triggerEvent (name, $children) {
      let vm = ($children || [])[0] || {};
      triggerEvent.call(vm, name)
      // 初始化前加载资源
      if (name === 'created') {
        this.loadResource(vm)
      }
    },
    // 加载资源
    loadResource (vm) {
      let res = vm.resource || vm.$attrs.resource || {}
      // 注入js
      if (res.js) {
        this.invoke(res.js)
      }
      // 注入css
      if (res.css) {
        domer.appendElement('style', {
          type: 'text/css',
          innerHTML: res.css
        })
      }
      // 引入文件
      let types = {
        script: { type: 'text/javascript', src: '{url}' },
        link: { rel: 'stylesheet', href: '{url}' }
      }
      if (Array.isArray(res.files)) {
        res.files = res.files.filter(item => {
          return !!String(item.url || '').trim() || !!String(item.content || '').trim()
        })
        res.files.forEach(item => {
          // 按名称注册
          if (item.name) {
            if (item.url) {
              $pig.register({
                map: {
                  [item.name]: item.url
                }
              })
            } else if (item.content) {
              let url = /^(https?:)?\/\//.test(item.name) ? item.name : location.origin + '/' + item.name
              $pig.register({
                map: {
                  [item.name]: url
                }
              })
              coder.resolve(item.content, $pig).then(mod => {
                mod = mod || {}
                $pig.set(url, mod)
              })
            }
          }
          // 地址加载
          else if (item.url) {
            let type = item.type || 'script'
            let node = types[type]
            for (let key in node) {
              node[key] = node[key].replace('{url}', item.url)
            }
            domer.appendElement(type, node)
          }
          // 内容加载
          else if (item.content) {
            this.invoke(item.content)
          }
        })
      }
    },

    invoke (content) {
      try {
        coder.resolve(content, $pig).then(mod => {
          let func = mod.default
          typeof func === 'function' && func.apply(this)
        })
      } catch (e) {
        console.log(e)
      }
    }
  },

  created () {
    this.syncComponent()
  },

  mounted () {
    setTimeout(() => {
      this.isLoading = false
    }, 250)
  }
}

// 触发自定义事件
function triggerEvent(name) {
  let events = this.events || this.$attrs?.events || {}
  let code = events[name]
  if (code) {
    coder.resolve(code, $pig).then(mod => {
      mod = mod || {}
      let func = mod.default
      typeof func === 'function' && func.apply(this)
    })
  }
}
</script>

<style lang="less">
.d-cprender-loading {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  text-align: center;
  color: #3391ff;
}
</style>
